﻿using System;
using System.Collections.Generic;
using System.Data;
using Flagwind.Collections;

namespace Flagwind.Data
{
	/// <summary>
	/// 表示数据访问的公共接口。
	/// </summary>
	public interface IDataAccess
	{
		#region 公共属性

		/// <summary>
		/// 获取默认的数据访问提供程序，注：支持读写分离模式。
		/// </summary>
		IDataProvider DefaultProvider
		{
			get;
		}

		NamedCollection<IDataProvider> DataProviders
		{
			get;
		}

		#endregion

		#region 新增方法

		/// <summary>
		/// 新增一个实体类数据。
		/// </summary>
		/// <param name="entity">实体对象。</param>
		/// <returns>受影响的记录数。</returns>
		int Insert(IEntity entity);

		/// <summary>
		/// 使用指定的数据访问提供程序，新增一个实体类数据。
		/// </summary>
		/// <param name="entity">实体对象。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>受影响的记录数。</returns>
		int Insert(IEntity entity, IDataProvider provider);

		/// <summary>
		/// 批量新增一组实体类数据。注：内部使用事物。
		/// </summary>
		/// <param name="entities">实体对象集合。</param>
		/// <returns>受影响的记录数。</returns>
		int Insert(IEnumerable<IEntity> entities);

		/// <summary>
		/// 使用指定的数据访问提供程序，批量新增一组实体类数据。注：内部使用事物。
		/// </summary>
		/// <param name="entities">实体对象集合。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>受影响的记录数。</returns>
		int Insert(IEnumerable<IEntity> entities, IDataProvider provider);

		#endregion

		#region 更新方法

		/// <summary>
		/// 更新一个实体类数据。
		/// </summary>
		/// <param name="entity">实体对象。</param>
		/// <returns>受影响的记录数。</returns>
		int Update(IEntity entity);

		/// <summary>
		/// 使用指定的数据访问提供程序，更新一个实体类数据。
		/// </summary>
		/// <param name="entity">实体对象。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>受影响的记录数。</returns>
		int Update(IEntity entity, IDataProvider provider);

		/// <summary>
		/// 批量更新一组实体类数据。注：内部使用事物。
		/// </summary>
		/// <param name="entities">实体对象集合。</param>
		/// <returns>受影响的记录数。</returns>
		int Update(IEnumerable<IEntity> entities);

		/// <summary>
		/// 使用指定的数据访问提供程序，批量更新一组实体类数据。注：内部使用事物。
		/// </summary>
		/// <param name="entities">实体对象集合。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>受影响的记录数。</returns>
		int Update(IEnumerable<IEntity> entities, IDataProvider provider);

		#endregion

		#region 删除方法

		/// <summary>
		/// 删除一个实体类数据。
		/// </summary>
		/// <param name="entity">实体对象。</param>
		/// <returns>受影响的记录数。</returns>
		int Delete(IEntity entity);

		/// <summary>
		/// 使用指定的数据访问提供程序，删除一个实体类数据。
		/// </summary>
		/// <param name="entity">实体对象。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>受影响的记录数。</returns>
		int Delete(IEntity entity, IDataProvider provider);

		/// <summary>
		/// 批量删除一组实体类数据。注：内部使用事物。
		/// </summary>
		/// <param name="entities">实体对象集合。</param>
		/// <returns>受影响的记录数。</returns>
		int Delete(IEnumerable<IEntity> entities);

		/// <summary>
		/// 使用指定的数据访问提供程序，批量删除一组实体类数据。注：内部使用事物。
		/// </summary>
		/// <param name="entities">实体对象集合。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>受影响的记录数。</returns>
		int Delete(IEnumerable<IEntity> entities, IDataProvider provider);

		#endregion

		#region 查询方法

		/// <summary>
		/// 根据实体查询表达式，查询实体对象集合。
		/// </summary>
		/// <typeparam name="T">实体类型。</typeparam>
		/// <param name="command">实体查询表达式。</param>
		/// <returns>实体对象集合。</returns>
		IEnumerable<T> Select<T>(Command command) where T : class, IEntity, new();

		/// <summary>
		/// 根据实体查询表达式及数据访问提供程序，查询实体对象集合。 
		/// </summary>
		/// <typeparam name="T">实体类型。</typeparam>
		/// <param name="command">实体查询表示。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>实体对象集合。</returns>
		IEnumerable<T> Select<T>(Command command, IDataProvider provider) where T : class, IEntity, new();

		/// <summary>
		/// 根据指定查询表达式，查询一个实体对象。
		/// </summary>
		/// <typeparam name="T">实体类型。</typeparam>
		/// <param name="command">查询表达式。</param>
		/// <returns>实体对象。</returns>
		T Find<T>(Command command) where T : class;

		/// <summary>
		/// 根据指定查询表达式及数据访问提供程序，查询一个实体对象。
		/// </summary>
		/// <typeparam name="T">实体类型。</typeparam>
		/// <param name="command">查询表达式。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>实体对象。</returns>
		T Find<T>(Command command, IDataProvider provider) where T : class;

		/// <summary>
		/// 填充实体对象，注：必须有主键值才可以填充成功。
		/// </summary>
		/// <param name="entity">包含主键值的实体对象。</param>
		/// <returns>填充后的实体对象。</returns>
		bool Fill(IEntity entity);

		/// <summary>
		/// 根据指定数据访问提供程序填充实体对象，注：必须有主键值才可以填充成功。
		/// </summary>
		/// <param name="entity">包含主键值的实体对象。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>填充后的实体对象。</returns>
		bool Fill(IEntity entity, IDataProvider provider);

		/// <summary>
		/// 检测实体类是否在数据库中存在，注：必须包含主键值。
		/// </summary>
		/// <param name="entity">包含主键值的实体对象。</param>
		/// <returns>布尔值，表示是否存在。</returns>
		bool Exists(IEntity entity);

		/// <summary>
		/// 根据指定的数据访问提供程序，检测实体类是否在数据库中存在，注：必须包含主键值。
		/// </summary>
		/// <param name="entity">包含主键值的实体对象。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>布尔值，表示是否存在。</returns>
		bool Exists(IEntity entity, IDataProvider provider);

		/// <summary>
		/// 检测查询表达式是否在数据存中存在。
		/// </summary>
		/// <param name="command">查询表达式。</param>
		/// <returns>布尔值，表示是否存在。</returns>
		bool Exists(Command command);

		/// <summary>
		/// 根据指定的数据访问提供程序，检测查询表达式是否在数据库中存在。
		/// </summary>
		/// <param name="command">查询表达式。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>布尔值，表示是否存在。</returns>
		bool Exists(Command command, IDataProvider provider);

		#endregion

		#region 执行方法

		/// <summary>
		/// 执行一个不返回结果集的 Command 表达式，例如更新，删除实体类的操作。
		/// </summary>
		/// <param name="command">Command 表达式。</param>
		/// <returns>受影响的记录数。</returns>
		int Execute(Command command);

		/// <summary>
		/// 使用指定的数据访问提供程序，执行一个不返回结果集的 Command 表达式，例如更新，删除实体类的操作。
		/// </summary>
		/// <param name="command">Command 表达式。</param>
		/// <param name="provider">数据访问提供程序。</param>
		/// <returns>受影响的记录数。</returns>
		int Execute(Command command, IDataProvider provider);

		#endregion

		#region 事务处理

		/// <summary>
		/// 打开连接并开启事务。
		/// </summary>
		void BeginTransaction();

		/// <summary>
		/// 开启事务并指定事务隔离级别。
		/// </summary>
		/// <param name="level">事务隔离级别。</param>
		void BeginTransaction(IsolationLevel level);

		/// <summary>
		/// 提交事务并关闭连接。
		/// </summary>
		void Commit();

		/// <summary>
		/// 回滚事务并关闭连接。
		/// </summary>
		void Rollback();

		#endregion
	}
}